from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db.models.signals import post_save

SPAM_STATUS_CHOICES = getattr(settings, 'SPAMBAYES_SPAM_STATUS_CHOICES', (
    ('SPAM', 'Spam'),
    ('HAM',  'Ham')),
)

HAM_LEVEL = getattr(settings, 'SPAMBAYES_HAM_LEVEL', 0.3)
SPAM_LEVEL = getattr(settings, 'SPAMBAYES_SPAM_LEVEL', 0.8)


class SpamStatus(models.Model):
    """ Track spam filtering/training of models through generic relations. """
    score = models.FloatField(blank=True, null=True)
    trained_as = models.CharField(max_length=4, blank=True, null=True, choices=SPAM_STATUS_CHOICES)
    trained = models.BooleanField(default=False)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    def __str__(self):
        return '<SpamStatus: %s for %s>'% (self.status(), self.content_object)
    
    def __unicode__(self):
        if self.score:
            score = ' (%s)' % self.score
        else:
            score = ''
        return '%s%s' % (self.status(), score)

    def is_trained(self):
        """ Return True if object has been trained. """
        return bool(self.trained_as)

    def is_spam(self):
        """ Return True if object is spam based on training or score. """
        if self.status() == "SPAM":
            return True
        return False

    def status(self):
        """ Return spam status as string based on training or score. """
        if self.is_trained():
            return self.trained_as
        return self.scored_as()

    def scored_as(self):
        """ Return spam staus as string based on score only. """
        if self.score < HAM_LEVEL:
            return "HAM"
        if self.score > SPAM_LEVEL:
            return "SPAM"
        return "UNSURE"

    class Meta:
        app_label = 'djangobayes'
        unique_together = ("content_type", "object_id")


def classify_on_save(sender, instance, created, **kwargs):
    if created and not instance.trained:
        from djangobayes.filter import filter, build_msg
        msg = build_msg(instance.content_object.comment, {
            'from': instance.content_object.user_name,
        })
        if not instance.trained:
            if instance.trained_as == 'SPAM':
                filter.train(msg, True)
            else:
                filter.train(msg, False)
           #try:
            instance.score = filter.score(msg)
            instance.trained = True
            instance.save()
           #except:
           #    # Sometimes spambayes raises an assertion error
           #    # and this error is gone on the second try .. whatever.
           #    instance.score = filter.score(msg)
           #    instance.trained = True
           #    instance.save()
           #else:
           #    pass

post_save.connect(classify_on_save, sender=SpamStatus, dispatch_uid='spam.classify.status')
